#pragma once
#include "common.hpp"
#include <unordered_map>
#include "Socket.hpp"
#include "utility.hpp"
#include <sstream>
#include <functional>


const std::string space_sep = " ";
const std::string line_sep = "\n";
const std::string kv_sep = ": ";
const std::string space_line = "\n\n";

const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";


class http_request
{
public:
    http_request()
        :_transfer_parameter(false)
    {}
    ~http_request() = default;


    //序列化 -- 服务端不用该接口, 客户端直接用浏览器
    // void serialize(){}

    //反序列化
    void deserialize(std::string& in_str/*会被更改*/)
    {
        std::cout << in_str << std::endl;
        //1. 处理首行(请求行)
        std::string first_line;
        utility::get_and_erase_a_line(in_str, first_line, line_sep);
        
        //2. 反序列化首行
        std::stringstream ss(first_line);
        ss >> _method >> _URI >> _http_version;
        if(_URI == "/")
            _URI = webroot + "/" + homepage;
        else
            _URI = webroot + _URI;


        //2.1 改造成可交互式的 -- 提供服务(GET方法通过URL传参, 我们这里不考虑POST方法, 因为它要解析正文, 有些麻烦)
        std::string args_sep = "?";
        size_t pos_args_sep = _URI.find(args_sep);
        if(pos_args_sep != std::string::npos)//有传参 --> 需要交换
        {
            _transfer_parameter = true;
            _args = _URI.substr(pos_args_sep + args_sep.size(), std::string::npos);
            _URI = _URI.substr(0, pos_args_sep);
        }


        std::cout << "_URI: " << _URI << std::endl; 
        std::cout << "_transfer parameter:  " << _transfer_parameter << std::endl; 
        std::cout << "_ages: " << _args << std::endl; 

        
        //3. 后面的报头和正文 TODO
        //.......



    }



    std::string get_URI() const
    {
        return _URI;
    }
    
    std::string get_args() const
    {
        return _args;
    }

    bool is_transfer_parameter() const
    {
        return _transfer_parameter;
    }


private:
    std::string _method;
    std::string _URI;
    std::string _http_version;
    std::unordered_map<std::string, std::string> _header;
    std::string _body;

    //这里仅实现了通过GET传递参数的方法, POST传参未实现
    std::string _args;
    bool _transfer_parameter;//是否传递参数
};



class http_response
{
public:
    http_response() = default;
    ~http_response() = default;

    void set_version(const std::string& version)
    {
        _http_version = version;
    }
    void set_code_and_explanation(int code)
    {
        _status_code = code;
        switch (_status_code)
        {
        case 200:
            _code_explanation = "OK";
            break;
        case 302:
            _code_explanation = "See Other";
            break;
        case 404:
            _code_explanation = "Not Found";
            break;
        //case ... 都应该设置在你的server内
        default:
            _code_explanation = "Code Not Set Up, miao~~~~";
            break;
        }
    }
    void header_push_kv(const std::string& key, const std::string& value)
    {
        auto it = _header.find(key);
        if(it != _header.end())//_header中已有当前属性 -- 当然也可以实现成覆盖式的
            return;

        _header.emplace(key, value);
    }


    std::string& get_body_ref()
    {
        return _body;
    }




    //序列化
    void serialize(std::string& out_str/*输出型参数*/)
    {
        std::string status_line = _http_version + space_sep + std::to_string(_status_code) + space_sep + _code_explanation + line_sep;
        std::string header_str;
        for(const auto& kv : _header)
        {
            header_str += kv.first + kv_sep + kv.second + line_sep;
        } 

        out_str = status_line + header_str + line_sep + _body;
    }

    //反序列化 -- 服务端不用该接口, 客户端直接用浏览器
    // void deserialize(){}



private:
    std::string _http_version;
    int _status_code; //404
    std::string _code_explanation; //"Not Found"
    std::unordered_map<std::string, std::string> _header;
    std::string _body;
};








using req_service_t = std::function<void(const http_request&, http_response&/*输出*/)>;



class http_protocol
{
public:
    http_protocol() = default;
    ~http_protocol() = default;

    //有bug, 会卡在find空行, 不知道问题
    // //解包
    // // 1. 判断报文完整性
    // // 2. 如果包含至少一个完整请求，就提取他, 并从移除它方便处理下一个
    // //                                     输入输出                                输出
    // bool get_and_erase_complete_package(std::string& package/*不一定是完整的*/, std::string& message)
    // {
    //     std::cout << "开始find空行" << std::endl;
    //     size_t pos_space_line = package.find(space_line/*"\n\n"*/);
    //     if(pos_space_line == std::string::npos)//报头不完整
    //         return false;
    //     //走到这代表找到了空行, 即package至少包含一个完整的报头
    //     std::cout << "find到空行了, 准备find Content-Length" << std::endl;

    //     size_t pos_content_len = package.find("Content-Length");
    //     std::cout << "准备find kv_sep" << std::endl;
    //     size_t pos_current_line_kv_sep = package.find(kv_sep, pos_content_len);
    //     std::cout << "准备find 行尾" << std::endl;
    //     size_t pos_current_line_end = package.find(line_sep, pos_content_len);
    //     std::cout << "准备substr content-len的value" << std::endl;
    //     std::string content_len_str = package.substr(pos_current_line_kv_sep + kv_sep.size(), pos_current_line_end);
    //     size_t content_len = std::stoi(content_len_str);
    //     std::cout << "stoi成功了, content_len是: " << content_len << std::endl;
    //     size_t front_part_len = pos_space_line - 0;//首行＋报头
    //     size_t complete_package_len = front_part_len + space_line.size() + content_len;//首行 + 报头 + 空行 + 正文
    //     std::cout << "complete_package_len是: " << complete_package_len << std::endl;
    //     if(package.size() < complete_package_len)//body不完整
    //         return false;

    //     message = package.substr(0, complete_package_len);
    //     package.erase(0, complete_package_len);
    //     return true;
    // }



    bool handle_func(const http_request& req, http_response& resp/*输出型*/)
    {
        //一: req有传参 -- 走交互服务逻辑
        if(req.is_transfer_parameter())
        {
            auto it = _req_services.find(req.get_URI());
            
            if(it != _req_services.end())//找到了
            {
                it->second(req, resp);
                return true;
            }
            else
            {
                LOG(wzx::log_level::WARNING) << req.get_URI() << "method not registered :(";
                //重定向到404
                resp.set_version("HTTP/1.1");//此处就随便设置了
                resp.set_code_and_explanation(302);//临时重定向
                resp.header_push_kv("Location", "404.html");
                return true;
            }
        }

        //二: req无传参 -- 应答静态网页
        std::string file_path = req.get_URI();
        if (file_path == "./wwwroot/favicon.ico")
        {
            LOG(wzx::log_level::DEBUG) << "用户请求: " << file_path << "忽略它";
            return false;
        }
        size_t content_length = 0;
        std::string file_content;
        if(utility::get_file_content(file_path, file_content))
        {
            //获取成功了
            resp.set_version("HTTP/1.1");//此处就随便设置了
            resp.set_code_and_explanation(200);
            resp.header_push_kv("Content-Type", utility::get_Content_Type(req.get_URI()));
            resp.header_push_kv("Content-Length", std::to_string(utility::get_filesize(file_path)));
            utility::get_file_content(file_path, resp.get_body_ref());

            return true;
        }
        else
        {
            //因为多种原因, 文件打开失败
            LOG(wzx::log_level::WARNING) << "client want get : " << file_path << ",  but not found!!!";

            //法1: 直接返回404.html
            // resp.set_version("HTTP/1.1");//此处就随便设置了
            // resp.set_code_and_explanation(404);
            // resp.header_push_kv("Content-Type", utility::get_Content_Type("./wwwroot/404.html"));
            // resp.header_push_kv("Content-Length", std::to_string(utility::get_filesize("./wwwroot/404.html")));
            // utility::get_file_content("./wwwroot/404.html", resp.get_body_ref());

            //法2: 重定向到404.html(让client再申请404.html) -- 重定向可以location本地资源, 也可以是外部资源
            resp.set_version("HTTP/1.1");//此处就随便设置了
            resp.set_code_and_explanation(302);//临时重定向
            resp.header_push_kv("Location", "404.html");


            return true;
        }

    }



    //server调用
    bool receive_request_and_send_response(std::shared_ptr<Socket>& sock_p, const Inet_Addr& client)
    {
        std::string in_buffer;//从socket_fd里读到的数据, 不一定完整
        // while(true) -- 不是长服务
        // {

        //1.读取socket, 接受请求报文 -- 不一定是完整的(大多时候是完整的) -- 我们这里假设取到的就是完整的, 因为解包的代码有未知bug
        if(sock_p->receive(in_buffer) == false)//客户端关闭了
            return false;
        
        // //2.取到完整请求报文
        // std::string recv_message_str;
        // if(get_and_erase_complete_package(in_buffer, recv_message_str) == false)//buffer里没有完整请求报文, 直接return(直接丢了)
        //     return false;

        //3.反序列化请求报文
        http_request recv_message_struct;
        recv_message_struct.deserialize(in_buffer);

        //4.处理报文
        http_response send_message_struct; 
        if(handle_func(recv_message_struct, send_message_struct) == false)//遇见申请favicon.ico了
            return false;

        //5.序列化应答报文
        std::string send_message_str;
        send_message_struct.serialize(send_message_str);

        //6.发送
        sock_p->send(send_message_str);

        return true;
        // }
    }

    bool register_req_service(const std::string& name, const req_service_t& service)
    {
        std::string uri = webroot + "/" + name;
        if(_req_services.find(uri) != _req_services.end())
        {
            LOG(wzx::log_level::WARNING) << "req_service: " << name << " already exists :(";
            return false;
        }

        _req_services.emplace(uri, service);
        return true;
    }   


private:
    std::unordered_map<std::string, req_service_t> _req_services;

};